#include "DSP2833x_Device.h"     // DSP2833x Headerfile Include File
#include "DSP2833x_Examples.h"   // DSP2833x Examples Include File

#include "DSP2833x_ADCLib.h"

//=====================================================================
// Declare some functions and macros
//=====================================================================

// ADC start parameters
#if (CPU_FRQ_150MHZ)     // Default - 150 MHz SYSCLKOUT
  #define ADC_MODCLK 0x3 // HSPCLK = SYSCLKOUT/2*ADC_MODCLK2 = 150/(2*3)   = 25.0 MHz
#endif
#if (CPU_FRQ_100MHZ)
  #define ADC_MODCLK 0x2 // HSPCLK = SYSCLKOUT/2*ADC_MODCLK2 = 100/(2*2)   = 25.0 MHz
#endif
#define ADC_CKPS   0x0   // ADC module clock = HSPCLK   = 25.0MHz/1 = 25.0 MHz => ADC Clock 40 ns
#define ADC_SHCLK  0x1   // S/H width in ADC module periods                        = 2 ADC clocks


#define ADC_usDELAY  5000L

//--------------------------------------------------------------------
// Declare some functions
//--------------------------------------------------------------------
void InitAdc(void);

//--------------------------------------------------------------------
// Enable ADC Triggers: PWM, External interface
//--------------------------------------------------------------------
void ADC_EnableTriggers(void){
	
}
//--------------------------------------------------------------------
// Clear Interrupt flags in the ISR
//--------------------------------------------------------------------
void ADC_ClearIntFlags(enum ADC_SEQUENCER SEQ){
	// Clear ADC Flag
	if (SEQ==ADC_SEQ2){
		AdcRegs.ADCST.bit.INT_SEQ2_CLR = 1;
	}
	else
		AdcRegs.ADCST.bit.INT_SEQ1_CLR = 1;
	// Clear ACK
	PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;
}


enum ADC_Status ADC_Busy(enum ADC_SEQUENCER SEQ){
	if (SEQ==ADC_SEQ2)
		return AdcRegs.ADCST.bit.SEQ2_BSY;
	else
		return AdcRegs.ADCST.bit.SEQ1_BSY;	
}
//-------------------------------------------------------------------
// Reset Sequencer
//-------------------------------------------------------------------
void ADC_ResetSequencer(enum ADC_SEQUENCER SEQ){
	if (SEQ==ADC_SEQ2)
		AdcRegs.ADCTRL2.bit.RST_SEQ2 = 1;
	else
		AdcRegs.ADCTRL2.bit.RST_SEQ1 = 1;
	
}
//--------------------------------------------------------------------
// Read data from ADC module
//--------------------------------------------------------------------
void ADC_Read(enum 	ADC_SEQUENCER SEQ, Uint16 * buffer, Uint16 num_of_channels){
	volatile Uint16 *ADC_RESULT_Base;	
	
	if (SEQ == ADC_SEQ2)
		ADC_RESULT_Base = &AdcRegs.ADCRESULT8;
	else
		ADC_RESULT_Base = &AdcRegs.ADCRESULT0;		

	// Read data
	while(num_of_channels--){
		*(buffer++) = (*(ADC_RESULT_Base++))>>4;
	};
}

//--------------------------------------------------------------------
// Start ADC Conversion
//--------------------------------------------------------------------
void ADC_StartConversion(enum 	ADC_SEQUENCER SEQ, Uint16 val){
	switch(SEQ){
		case ADC_SEQ1:
		case ADC_SEQ:
			AdcRegs.ADCTRL2.bit.SOC_SEQ1 = val;
			break;
		case ADC_SEQ2:
			AdcRegs.ADCTRL2.bit.SOC_SEQ2 = val;
			break;
	};
}
//--------------------------------------------------------------------
// Set maximum conversion
//--------------------------------------------------------------------
void ADC_SetMaxConversion(enum 	ADC_SEQUENCER SEQ, Uint16 val){
	if (SEQ == ADC_SEQ2)
		AdcRegs.ADCMAXCONV.bit.MAX_CONV2 = val-1;
	else
		AdcRegs.ADCMAXCONV.bit.MAX_CONV1 = val-1;

}

//--------------------------------------------------------------------
// ADC Select channel
//--------------------------------------------------------------------	
void ADC_SelectChannel(enum ADC_CONV_Number CONV_Num, Uint16 adc_input_offset){
	volatile Uint16 * ADCCHSEL_Base_Addr= &AdcRegs.ADCCHSELSEQ1.all;
	Uint16 reg_offset = CONV_Num/4;
	
	*(ADCCHSEL_Base_Addr + reg_offset) |= adc_input_offset<<(4*(CONV_Num%4));
	
	return;		
}

void ADC_SelectAllChannel(Uint16 adc_port){
	Uint16 temp = adc_port + (adc_port<<4) + (adc_port<<8) + (adc_port<<12);
	AdcRegs.ADCCHSELSEQ1.all = temp;
	AdcRegs.ADCCHSELSEQ2.all = temp;
	AdcRegs.ADCCHSELSEQ3.all = temp;
	AdcRegs.ADCCHSELSEQ4.all = temp;
}

//--------------------------------------------------------------------
// Initialize Interrupt feature
//-------------------------------------------------------------------- 
void ADC_InitInterrupt(enum ADC_SEQUENCER SEQ, enum ADC_Int_Mode int_mode, PINT Int_Fcn){
	switch(SEQ){
		case ADC_SEQ1:
			AdcRegs.ADCTRL2.bit.INT_ENA_SEQ1 = 1;			// Enable ADC Interrupt
			AdcRegs.ADCTRL2.bit.INT_MOD_SEQ1 = int_mode;
			AdcRegs.ADCST.bit.INT_SEQ1_CLR = 1;				// Clear Interrupt flag
			
			// ADC_SEQ1: Group 1, int 1
			PieCtrlRegs.PIEIER1.bit.INTx1 = 1;
			IER |= M_INT1;
			
			// Assign interrupt func
			EALLOW;
			PieVectTable.SEQ1INT =  Int_Fcn;
			EDIS;
			
			break;
		case ADC_SEQ2:
			AdcRegs.ADCTRL2.bit.INT_ENA_SEQ2 = 1;
			AdcRegs.ADCTRL2.bit.INT_MOD_SEQ2 = int_mode;
			AdcRegs.ADCST.bit.INT_SEQ2_CLR = 1;
			
			// ADC_SEQ2: Group 1, int 2
			PieCtrlRegs.PIEIER1.bit.INTx2 = 1;
			IER |= 	M_INT1;		
			
			break;
		case ADC_SEQ:
			AdcRegs.ADCTRL2.bit.INT_ENA_SEQ1 = 1;			// Enable ADC Interrupt
			AdcRegs.ADCTRL2.bit.INT_MOD_SEQ1 = int_mode;
			AdcRegs.ADCST.bit.INT_SEQ1_CLR = 1;				// Clear Interrupt flag
			
			// ADC: Group 1, int 6
			PieCtrlRegs.PIEIER1.bit.INTx6 = 1;
			IER |= M_INT1;
			
			EALLOW;
			PieVectTable.ADCINT = Int_Fcn;
			EDIS;
			
			break;
	};
}

//--------------------------------------------------------------------
// Init ADC Module
//--------------------------------------------------------------------
void ADC_Init(enum ADC_Sequencer_Mode adc_sequencer_mode,enum ADC_Sampling_Mode adc_sampling_mode,
			  enum ADC_Operation_Mode adc_operation_mode,enum ADC_Override_Mode adc_override_mode){
	
	//---------------------------------------------------------
	// Step 1: Enable ADC clock and powerup ADC Module
	//--------------------------------------------------------- 
	
	// Initializes ADC to a known state
	InitAdc();
	
	// Config ADC Reference Select
	AdcRegs.ADCREFSEL.bit.REF_SEL = 0x00;		// External reference: 2.048V on ADCREFIN
						// 00: Internal reference (Default)
						// 01: External reference: 2.048V on ADCREFIN
						// 10: External reference: 1.500V on ADCREFIN
						// 11: External reference: 1.024V on ADCREFIN
						
	// Emulator mode
	AdcRegs.ADCTRL1.bit.SUSMOD = 0; // Suspend mode
						// 00: Emulation suspend is ignored
						// 01: sequencer and other swapper logic stops after current SEQUENCE is complete
						// 10: Sequencer and other wrapper logic stops after current CONVERSION is complete
						// 11: Sequencer and other wrapper logic stops immediately on emulation suspend						
						
	//---------------------------------------------------------
	// Step 2: Config ADC Clock and S/H width
	//---------------------------------------------------------
	// Config ADC Clock
	EALLOW;
   	SysCtrlRegs.HISPCP.all = ADC_MODCLK;	// HSPCLK = SYSCLKOUT/ADC_MODCLK = 25.0 MHz => ADC Clock 40 ns
   	EDIS;     	
   	
   	AdcRegs.ADCTRL3.bit.ADCCLKPS = ADC_CKPS;	//ADC module clock = HSPCLK  = 25.0MHz/1 = 25.0 MHz => ADC Clock 40 ns
   						// Fclk = HSPCLK /(2*ADC_CKPS) when ADC_CKPS != 0
   						// Fclk = HSPCLK when ADC_CKPS = 0
   	AdcRegs.ADCTRL1.bit.CPS = 0;	// ADCCLK = Fclk/(CPS+1) = 25 MHz  	
   	
   	// Config S/H width in ADC module periods  
   	AdcRegs.ADCTRL1.bit.ACQ_PS = ADC_SHCLK;  // Sequential mode: Sample rate   = 1/[(2+ACQ_PS)*ADC clock in ns]
                    	//                     = 1/(3*40ns) =8.3MHz (for 150 MHz SYSCLKOUT)
					    //                     = 1/(3*80ns) =4.17MHz (for 100 MHz SYSCLKOUT)
					    // If Simultaneous mode enabled: Sample rate = 1/[(3+ACQ_PS)*ADC clock in ns]
	//---------------------------------------------------------
	// Step 3: Setup sampling mode, ....
	//---------------------------------------------------------
	AdcRegs.ADCTRL1.bit.SEQ_CASC = adc_sequencer_mode;	// Dual-sequencers or Cascaded
	AdcRegs.ADCTRL3.bit.SMODE_SEL = adc_sampling_mode;	// Sequential or Simultaneous
	AdcRegs.ADCTRL1.bit.CONT_RUN = adc_operation_mode;	// Start/Stop or Continuous mode
	AdcRegs.ADCTRL1.bit.SEQ_OVRD = adc_override_mode;	// Override mode
		
			  	
}
//--------------------------------------------------------------------
// Initialize ADC: This function initializes ADC to a known state.
// Copy from DSP2833x_Adc.c in Common/Source folder: must be updated when new version released.
//--------------------------------------------------------------------

void InitAdc(void)
{
    extern void DSP28x_usDelay(Uint32 Count);


    // *IMPORTANT*
	// The ADC_cal function, which  copies the ADC calibration values from TI reserved
	// OTP into the ADCREFSEL and ADCOFFTRIM registers, occurs automatically in the
	// Boot ROM. If the boot ROM code is bypassed during the debug process, the
	// following function MUST be called for the ADC to function according
	// to specification. The clocks to the ADC MUST be enabled before calling this
	// function.
	// See the device data manual and/or the ADC Reference
	// Manual for more information.

	EALLOW;
	SysCtrlRegs.PCLKCR0.bit.ADCENCLK = 1;
	ADC_cal();
	EDIS;




    // To powerup the ADC the ADCENCLK bit should be set first to enable
    // clocks, followed by powering up the bandgap, reference circuitry, and ADC core.
    // Before the first conversion is performed a 5ms delay must be observed
	// after power up to give all analog circuits time to power up and settle

    // Please note that for the delay function below to operate correctly the
	// CPU_RATE define statement in the DSP2833x_Examples.h file must
	// contain the correct CPU clock period in nanoseconds.

    AdcRegs.ADCTRL3.all = 0x00E0;  // Power up bandgap/reference/ADC circuits
    DELAY_US(ADC_usDELAY);         // Delay before converting ADC channels
}

//===========================================================================
// End of file.
//===========================================================================
